#include <iostream>
#include <fstream>
#include <vector>
#include <ctime>
#include <NTL/ZZ.h>

NTL_CLIENT

#define N 10000

// multiplicative method of generating random numbers
ZZ next_mult_num(ZZ x0, ZZ l, ZZ m) {
	
	// to make odd value
	if (!IsOdd(x0))
		x0 += 1;

	// next number
	return MulMod(x0, l, m);
}

// sensor Fibonacci
double next_fib_num(vector<double> Xi, const int a, const int b) {
	
	double Xka, Xkb;

	Xka = Xi[Xi.size() - a];
	Xkb = Xi[Xi.size() - b];

	if (Xka > Xkb)
		return Xka - Xkb;

	return Xka - Xkb + 1;
}

// convert Bytes to double
double conv2double(unsigned char *p, long n) {

	double num = 0.0;
	for (long i = 1; i < n; i++)
		num = num + p[n - i]*pow(256.0, -i);
	return num;
}

// 
int main(int argc, char **argv) {

	const int a = 10, b = 15;
	unsigned char *p;
	vector<double> x;
	ZZ x0, l, m;
	long n;

	// initialization
	srand(time(NULL));
	x0 = (long)rand();
	l = 120;
	m = power2_ZZ(32);	

	// to compute multiplicative sequence, length MAX(a,b)
	for (int i = 0; i < b; i++) {
		x0 = next_mult_num(x0, l, m);
		n = NumBytes(x0);
		p = new unsigned char[n];
		BytesFromZZ(p, x0, n);
		x.push_back(conv2double(p, n));
		delete[] p;		
	}

	// to compute Fibonacci sequence
	for (int i = 0; i < N; i++)
		x.push_back(next_fib_num(x, a, b));
	
	// save sequence in file
	ofstream outfile("fib_seq.txt");
	if (!outfile.is_open()) {
		cout << "Error opening file";
		exit(1);
	}
	for (int i = b; i < x.size(); i++)
		outfile << x[i] << "\n";
	outfile.close();

	return 0;
}